export default class ColumnManager {
  constructor (columns) {
    this.columns = columns
    this._cached = {}
  }

  isAnyColumnsFixed () {
    return this._cache('isAnyColumnsFixed', () => {
      return this.columns.some(column => !!column.fixed)
    })
  }

  isAnyColumnsLeftFixed () {
    return this._cache('isAnyColumnsLeftFixed', () => {
      return this.columns.some(
        column => column.fixed === 'left' || column.fixed === true
      )
    })
  }

  isAnyColumnsRightFixed () {
    return this._cache('isAnyColumnsRightFixed', () => {
      return this.columns.some(
        column => column.fixed === 'right'
      )
    })
  }

  leftColumns () {
    return this._cache('leftColumns', () => {
      return this.groupedColumns().filter(
        column => column.fixed === 'left' || column.fixed === true
      )
    })
  }

  rightColumns () {
    return this._cache('rightColumns', () => {
      return this.groupedColumns().filter(
        column => column.fixed === 'right'
      )
    })
  }

  leafColumns () {
    return this._cache('leafColumns', () =>
      this._leafColumns(this.columns)
    )
  }

  leftLeafColumns () {
    return this._cache('leftLeafColumns', () =>
      this._leafColumns(this.leftColumns())
    )
  }

  rightLeafColumns () {
    return this._cache('rightLeafColumns', () =>
      this._leafColumns(this.rightColumns())
    )
  }

  // add appropriate rowspan and colspan to column
  groupedColumns () {
    return this._cache('groupedColumns', () => {
      const _groupColumns = (columns, currentRow = 0, parentColumn = {}, rows = []) => {
        // track how many rows we got
        rows[currentRow] = rows[currentRow] || []
        const grouped = []
        const setRowSpan = column => {
          const rowSpan = rows.length - currentRow
          if (column &&
            !column.children && // parent columns are supposed to be one row
            rowSpan > 1 &&
            (!column.rowSpan || column.rowSpan < rowSpan)
          ) {
            column.rowSpan = rowSpan
          }
        }
        columns.forEach((column, index) => {
          const newColumn = { ...column }
          rows[currentRow].push(newColumn)
          parentColumn.colSpan = parentColumn.colSpan || 0
          if (newColumn.children && newColumn.children.length > 0) {
            newColumn.children = _groupColumns(newColumn.children, currentRow + 1, newColumn, rows)
            parentColumn.colSpan += newColumn.colSpan
          } else {
            parentColumn.colSpan++
          }
          // update rowspan to all same row columns
          for (let i = 0; i < rows[currentRow].length - 1; ++i) {
            setRowSpan(rows[currentRow][i])
          }
          // last column, update rowspan immediately
          if (index + 1 === columns.length) {
            setRowSpan(newColumn)
          }
          grouped.push(newColumn)
        })
        return grouped
      }
      return _groupColumns(this.columns)
    })
  }

  reset (columns) {
    this.columns = columns
    this._cached = {}
  }

  _cache (name, fn) {
    if (name in this._cached) {
      return this._cached[name]
    }
    this._cached[name] = fn()
    return this._cached[name]
  }

  _leafColumns (columns) {
    const leafColumns = []
    columns.forEach(column => {
      if (!column.children) {
        leafColumns.push(column)
      } else {
        leafColumns.push(...this._leafColumns(column.children))
      }
    })
    return leafColumns
  }
}
